var Validator = {};
(function(){
	/**
	 * 校验类型与数字映射表
	 * maxDBColumnSize 指数据库字段的最大长度，中文算两个
	 * maxCharLength 指js算出来的字符个数最大值 中文算一个
	 */
	var typeTable = {
		'require' : 1,
		'maxDBColumnSize' : 2,
		'minDBColumnSize' : 3,
		'maxCharLength' : 4,
		'minCharLength' : 5,
		'max' : 6,
		'min' : 7,
		'intType' : 8,
		'floatType' : 9,
		'alphabetAndNum' : 10,
		'numType' : 11,
		'nonCN' : 12,
		'positiveInt' : 13,
		'moble' : 13,
		'positiveNumType' : 14,
		'telephone' : 15,
		'idcard':16,
		'dateFrom':17,
		'readCard':18,
		'dateFrom1':19
	};
	var type2TipsTable = {
		'require' : '该字段必须输入',
		'maxDBColumnSize' : '该字段最大长度为：',
		'minDBColumnSize' : '该字段最小长度为：',
		'maxCharLength' : '该字段最大长度为：',
		'minCharLength' : '该字段最小长度为：',
		'max' : '该字段最大值为：',
		'min' : '该字段最小值为：',
		'intType' : '该字段只能是整数',
		'floatType' : '该字段只能是小数',
		'alphabetAndNum' : '该字段只能是字母和数字',
		'numType' : '该字段只能是数字',
		'nonCN' : '该字段不能含有中文',
		'positiveInt' : '该字段只能是正整数',
		'moble' : '该字段为手机号码，只能是纯数字',
		'positiveNumType' : '该字段必须为非负数',
		'telephone' :'该字段只能是纯数字或者类似"0512-50501234"的形式',
		'idcard':'身份证号码输入不合法',
		'dateFrom':'日期格式不对,应为"yyyy-MM-dd HH:mm"',
		'readCard':'请先读卡',
		'dateFrom1':'日期格式不对,应为"yyyy-MM-dd"'
	};
	
	/**
	 * 必输
	 * @param {Object} val
	 */
	var testRequire = function(val){
		//去空
		val=val.replace(/(^\s*)|(\s*$)/g, "");
		if((typeof val) === 'undefined' || val === null || val === ''){
			return false;
		}
		return true;
	};
	
	var testMaxDBColumnSize = function(val, spec){
		if((typeof val) === 'undefined' || val === null || val === ''){
			return true;
		}
		var valChars = val.split("");
		var zhCNCharCount = 0;
		for(var i=0; i < valChars.length; i++){
			if(/[\u4E00-\u9FA5\uF900-\uFA2D]/.test(valChars[i])){
				zhCNCharCount = zhCNCharCount + 1;
			}
		}
		
		// 汉字一个算两个长度
		var totalLength = val.length + zhCNCharCount;
		var specV = spec;
		if((typeof spec) === 'string'){
			if(/^-?\d+$/.test(spec)){
				specV = parseInt(spec);
			}
			else if(/^(-?\d+)(\.\d+)?$/.test(val)){
				specV = parseFloat(spec);
			}
		}
		if(totalLength > specV){
			return false;
		} else {
			return true;
		}
	};
	
	var testMinDBColumnSize = function(val, spec){
		if((typeof val) === 'undefined' || val === null || val === ''){
			return false;
		}
		var valChars = val.split("");
		var zhCNCharCount = 0;
		for(var i=0; i < valChars.length; i++){
			if(/[\u4E00-\u9FA5\uF900-\uFA2D]/.test(valChars[i])){
				zhCNCharCount = zhCNCharCount + 1;
			}
		}
		
		// 汉字一个算两个长度
		var totalLength = val.length + zhCNCharCount;
		var specV = spec;
		if((typeof spec) === 'string'){
			if(/^-?\d+$/.test(spec)){
				specV = parseInt(spec);
			}
			else if(/^(-?\d+)(\.\d+)?$/.test(val)){
				specV = parseFloat(spec);
			}
		}
		if(totalLength < specV){
			return false;
		} else {
			return true;
		}
	};
	
	var testMaxCharLength = function(val, spec){
		if((typeof val) === 'undefined' || val === null || val === ''){
			return true;
		}
		var specV = spec;
		if((typeof spec) === 'string'){
			if(/^-?\d+$/.test(spec)){
				specV = parseInt(spec);
			}
			else if(/^(-?\d+)(\.\d+)?$/.test(val)){
				specV = parseFloat(spec);
			}
		}
		if(val.length > specV){
			return false;
		} else {
			return true;
		}
	};
	
	var testMinCharLength = function(val, spec){
		if((typeof val) === 'undefined' || val === null || val === ''){
			return false;
		}
		var specV = spec;
		if((typeof spec) === 'string'){
			if(/^-?\d+$/.test(spec)){
				specV = parseInt(spec);
			}
			else if(/^(-?\d+)(\.\d+)?$/.test(val)){
				specV = parseFloat(spec);
			}
		}
		if(val.length < specV){
			return false;
		} else {
			return true;
		}
	};
	
	var testMax = function(val, spec){
		if((typeof val) === 'undefined' || val === null || val === ''){
			return true;
		}
		if(isNaN(val)){
			return false;
		}
		var specV = spec;
		if((typeof spec) === 'string'){
			if(/^-?\d+$/.test(spec)){
				specV = parseInt(spec);
			}
			else if(/^(-?\d+)(\.\d+)?$/.test(val)){
				specV = parseFloat(spec);
			}
		}
		var valNum = val;
		if((typeof val) === 'string'){
			if(/^-?\d+$/.test(val)){
				valNum = parseInt(val);
			}
			else if(/^(-?\d+)(\.\d+)?$/.test(val)){
				valNum = parseFloat(val);
			}
		}
		if(valNum > specV){
			return false;
		} else {
			return true;
		}
	};
	
	var testMin = function(val, spec){
		if((typeof val) === 'undefined' || val === null || val === ''){
			return true;
		}
		if(isNaN(val)){
			return false;
		}
		var valNum = val;
		var specV = spec;
		if((typeof spec) === 'string'){
			if(/^-?\d+$/.test(spec)){
				specV = parseInt(spec);
			}
			else if(/^(-?\d+)(\.\d+)?$/.test(val)){
				specV = parseFloat(spec);
			}
		}
		if((typeof val) === 'string'){
			if(/^-?\d+$/.test(val)){
				valNum = parseInt(val);
			}
			else if(/^(-?\d+)(\.\d+)?$/.test(val)){
				valNum = parseFloat(val);
			}
		}
		if(valNum < specV){
			return false;
		} else {
			return true;
		}
	};
	
	var testIntType = function(val){
		if((typeof val) === 'undefined' || val === null || val === ''){
			return true;
		}
		if(isNaN(val)){
			return false;
		}
		var valStr = val
		if((typeof val) === 'number'){
			valStr = val + ""; 	
		}
		return /^-?\d+$/.test(val);
	};
	
	var testPositiveInt = function(val){
		if((typeof val) === 'undefined' || val === null || val === ''){
			return true;
		}
		if(isNaN(val)){
			return false;
		}
		var valStr = val
		if((typeof val) === 'number'){
			valStr = val + ""; 	
		}
		return /^\d+$/.test(val);
	};
	
	var testFloatType = function(val){
		if((typeof val) === 'undefined' || val === null || val === ''){
			return true;
		}
		if(isNaN(val)){
			return false;
		}
		var valStr = val
		if((typeof val) === 'number'){
			valStr = val + ""; 	
		}
		return /^(-?\d+)(\.\d+)?$/.test(val);
	};
	
	var testNumType = function(val){
		if((typeof val) === 'undefined' || val === null || val === ''){
			return true;
		}
		return !isNaN(val);
	};
	
	var testPositiveNumType = function(val){
		if((typeof val) === 'undefined' || val === null || val === ''){
			return true;
		}
		if(isNaN(val)){
			return false;
		}
		var valNum = val + "";
		if((typeof val) === 'string'){
			if(/^-?\d+$/.test(val)){
				valNum = parseInt(val);
			}
			else if(/^(-?\d+)(\.\d+)?$/.test(val)){
				valNum = parseFloat(val);
			}
			else{
				return false;
			}
		}
		if (valNum < 0){
			return false;
		}
		return true;
	};
	
	var testTelephone = function(val){
		if((typeof val) === 'undefined' || val === null || val === ''){
			return true;
		}
		return /^([0-9]{3,4}-)?[0-9]{7,8}$/.test(val) || /^\d+$/.test(val);
	};
	
	var testAlphabetAndNum = function(val){
		if((typeof val) === 'undefined' || val === null || val === ''){
			return true;
		}
		if(!isNaN(val)){
			return true;
		}
		return /^[A-Za-z0-9]+$/.test(val);
	};
	
	var testNonCN = function(val){
		if((typeof val) === 'undefined' || val === null || val === ''){
			return true;
		}
		var valChars = val.split("");
		for(var i=0; i < valChars.length; i++){
			if(/[\u4E00-\u9FA5\uF900-\uFA2D]/.test(valChars[i])){
				return false;
			}
		}
		return true;
	};
	/***验证是否是身份证号码*/
	var testIdCardNo=function(num){
		 num = num.toUpperCase();   
	     //身份证号码为15位或者18位，15位时全为数字，18位前17位为数字，最后一位是校验位，可能为数字或字符X。    
	     if (!(/(^\d{15}$)|(^\d{17}([0-9]|X)$)/.test(num))){   
	          return false;  
	     }
	     return true;
	};
	
	var testDate = function (val)
	{
		var reTimeReg =/^([0-9]{3}[1-9]|[0-9]{2}[1-9][0-9]{1}|[0-9]{1}[1-9][0-9]{2}|[1-9][0-9]{3})-(((0[13578]|1[02])-(0[1-9]|[12][0-9]|3[01]))|((0[469]|11)-(0[1-9]|[12][0-9]|30))|(02-(0[1-9]|[1][0-9]|2[0-8]))) ([0-1]?[0-9]|2[0-3]):([0-5][0-9])$/;
		if((typeof val) === 'undefined' || val === null || val === ''){
			return true;
		}
		if(!reTimeReg.test(val))
		{return false;}
		return true;
	}
	
	var testReadCard = function (val)
	{
		if((typeof val) === 'undefined' || val === null || val === ''){
			return false;
		}
		return true;
	}
	
	var testDate1 = function (val)
	{
		var reTimeReg =/^([0-9]{3}[1-9]|[0-9]{2}[1-9][0-9]{1}|[0-9]{1}[1-9][0-9]{2}|[1-9][0-9]{3})-(((0[13578]|1[02])-(0[1-9]|[12][0-9]|3[01]))|((0[469]|11)-(0[1-9]|[12][0-9]|30))|(02-(0[1-9]|[1][0-9]|2[0-8])))$/;
		if((typeof val) === 'undefined' || val === null || val === ''){
			return true;
		}
		if(!reTimeReg.test(val))
		{return false;}
		return true;
	}
	/**
	 * 返回是否合法 false 是不合法
	 * @param {Object} value
	 * @param {Object} type
	 * @param {Object} spec
	 */
	Validator.validateItem = function(value, type, spec){
		var typeVal = typeTable[type];
		switch (typeVal){
			case 1:
			    return testRequire(value);
			case 2:
			    return testMaxDBColumnSize(value, spec);
			case 3:
			    return testMinDBColumnSize(value, spec);
			case 4:
			    return testMaxCharLength(value, spec);
			case 5:
			    return testMinCharLength(value, spec);
			case 6:
			    return testMax(value, spec);
			case 7:
			    return testMin(value, spec);
			case 8:
			    return testIntType(value, spec);
			case 9:
			    return testFloatType(value, spec);
			case 10:
			    return testAlphabetAndNum(value, spec);
			case 11:
			    return testNumType(value, spec);
			case 12:
			    return testNonCN(value, spec);
			case 13:
			    return testPositiveInt(value);
			case 14:
			    return testPositiveNumType(value); 
			case 15:
			    return testTelephone(value); 
			case 16:
				return testIdCardNo(value);
			case 17:
				return testDate(value);
			case 18:
				return testReadCard(value);
			case 19:
				return testDate1(value);
			default:
			    return false;
		}
	};
	
	/**
	 * 增加错误提示
	 */
	var addTips = function(jElement, tips){
		removeTips(jElement);
		var tipsEle = $('<div class="b-validate-tips" style="color:#AE1027;"> <i class="glyphicon glyphicon-remove" ></i> <span>'
		    + tips
		    + '</span> </div>');
		jElement.parent().append(tipsEle);
	};
	
	/**
	 * 移除错误提示
	 */
    var removeTips = function(jElement){
    	try{
    		$(".b-validate-tips", jElement.parent()).remove();
    	}catch(e){}
	};
	
	/**
	 * 校验ui  所有指定了b-validate class的都会被校验
	 * 返回校验是否通过
	 */
	Validator.validate = function(scopeArg){
		var allInput = [];
		if ((typeof scopeArg) === 'undefined' || scopeArg === null) {
			allInput = $(".b-validate");
		} else {
			allInput = $(".b-validate", scopeArg);
		}
		var isOk = true;
		$(allInput).each(function(index,element){
			var value = $(element).val();
			var isOk4Item = true;
			var allValidateFeatureStr = $(element).attr('validate-feature');
			if ((typeof allValidateFeatureStr) !== 'undefined' && allValidateFeatureStr !== null) {
				var allValidateFeature = allValidateFeatureStr.split(",")
				for (var i=0; i<allValidateFeature.length;i++){
					var res = Validator.validateItem(value, allValidateFeature[i]);
					if(res === false){
						if(isOk){
							// $(element).focus();
						}
						isOk = false;
						var tips = type2TipsTable[allValidateFeature[i]];
						/**
						 * <div class="b-validate-tips" style="color:#AE1027;">
							<i class="glyphicon glyphicon-remove" ></i>
							<span>出错了</span>
							</div>
						 */
						addTips($(element), tips);
						isOk4Item = false;
						return;
					}
				}
			}
			
			var maxCon = $(element).attr('validate-max');
			if ((typeof maxCon) !== 'undefined' && maxCon !== null){
				var res = Validator.validateItem(value, 'max', maxCon);
				if(res === false) {
					if(isOk){
						// $(element).focus();
					}
					isOk = false;
					var tips = type2TipsTable['max'] + maxCon;
					addTips($(element), tips);
					isOk4Item = false;
					return;
				}
			}
			
			var minCon = $(element).attr('validate-min');
			if ((typeof minCon) !== 'undefined' && minCon !== null){
				var res = Validator.validateItem(value, 'min', minCon);
				if(res === false) {
					if(isOk){
						// $(element).focus();
					}
					isOk = false;
					isOk4Item = false;
					var tips = type2TipsTable['min'] + minCon;
					addTips($(element), tips);
					return;
				}
			}
			
			var maxDBColumnSizeCon = $(element).attr('validate-maxDBColumnSize');
			if ((typeof maxDBColumnSizeCon) !== 'undefined' && maxDBColumnSizeCon !== null){
				var res = Validator.validateItem(value, 'maxDBColumnSize', maxDBColumnSizeCon);
				if(res === false) {
					if(isOk){
						// $(element).focus();
					}
					isOk = false;
					isOk4Item = false;
					var tips = type2TipsTable['maxDBColumnSize'] + maxDBColumnSizeCon;
					addTips($(element), tips);
					return;
				}
			}
			
			var minDBColumnSize = $(element).attr('validate-minDBColumnSize');
			if ((typeof minDBColumnSize) !== 'undefined' && minDBColumnSize !== null){
				var res = Validator.validateItem(value, 'minDBColumnSize', minDBColumnSize);
				if(res === false) {
					if(isOk){
						// $(element).focus();
					}
					isOk = false;
					isOk4Item = false;
					var tips = type2TipsTable['minDBColumnSize'] + minDBColumnSize;
					addTips($(element), tips);
					return;
				}
			}
			
			var maxCharLength = $(element).attr('validate-maxCharLength');
			if ((typeof maxCharLength) !== 'undefined' && maxCharLength !== null){
				var res = Validator.validateItem(value, 'maxCharLength', maxCharLength);
				if(res === false) {
					if(isOk){
						// $(element).focus();
					}
					isOk = false;
					isOk4Item = false;
					var tips = type2TipsTable['maxCharLength'] + maxCharLength;
					addTips($(element), tips);
					return;
				}
			}
			
			var minCharLength = $(element).attr('validate-minCharLength');
			if ((typeof minCharLength) !== 'undefined' && minCharLength !== null){
				var res = Validator.validateItem(value, 'minCharLength', minCharLength);
				if(res === false) {
					if(isOk){
						// $(element).focus();
					}
					isOk = false;
					isOk4Item = false;
					var tips = type2TipsTable['minCharLength'] + minCharLength;
					addTips($(element), tips);
					return;
				}
			}
			if(isOk4Item){
				removeTips($(element));
			}
		});
		return isOk;
	};
	
	// onchage触发校验
	$(document).ready(function(){
		 $('.b-validate').bind('change', function(e){
			 Validator.validate($($(e.target).parent()));
		 });
	 });
})();
